﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;

namespace GMUtilitiesDotNet.Helpers
{
    /// <summary>
    /// A small helper class that has a method to help create
    /// PropertyChangedEventArgs when using the INotifyPropertyChanged
    /// interface
    /// </summary>
    public static class ObservableHelper
    {
        #region Public Methods

        /// <summary>
        /// Creates PropertyChangedEventArgs
        /// </summary>
        /// <param name="propertyExpression">Expression to make 
        /// PropertyChangedEventArgs out of</param>
        /// <returns>PropertyChangedEventArgs</returns>
        public static PropertyChangedEventArgs CreateArgs<T>(
            Expression<Func<T, Object>> propertyExpression)
        {
            return new PropertyChangedEventArgs(
                GetPropertyName<T>(propertyExpression));
        }

        /// <summary>
        /// Creates PropertyChangedEventArgs
        /// </summary>
        /// <param name="propertyExpression">Expression to make 
        /// PropertyChangedEventArgs out of</param>
        /// <returns>PropertyChangedEventArgs</returns>
        public static string GetPropertyName<T>(
            Expression<Func<T, Object>> propertyExpression)
        {
            var lambda = propertyExpression as LambdaExpression;
            MemberExpression memberExpression;
            if (lambda.Body is UnaryExpression)
            {
                var unaryExpression = lambda.Body as UnaryExpression;
                memberExpression = unaryExpression.Operand as MemberExpression;
            }
            else
            {
                memberExpression = lambda.Body as MemberExpression;
            }

            var propertyInfo = memberExpression.Member as PropertyInfo;

            return propertyInfo.Name;
        }

        /// <summary>
        /// Helper method for getting name of the local variable.
        /// Uses anonymous objects to get variable name.
        /// 
        /// Usage:
        /// <example>
        /// <code>
        /// int myVariable;
        /// string variableName = NameOf(new { myVariable }); // returns string "myVariable"
        ///  </code>
        ///  </example>
        ///  
        /// </summary>
        /// <typeparam name="T">Anonymous type</typeparam>
        /// <param name="anonymousObject">The anonymous object having one property with 
        /// name equal to local variable name.</param>
        /// <returns>String name of local variable</returns>
        public static string NameOf<T>(T anonymousObject) where T : class
        {
            PropertyInfo[] propertyInfos = typeof(T).GetProperties();

            // anonymous object must have only one property - created based on the local variable name
            if (propertyInfos.Length != 1)
            {
                throw new ArgumentException("Anonymous object should have only one property");
            }

            return propertyInfos[0].Name;
        }

        #endregion
    }
}
